package com.xiumu.service.sys.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiumu.common.core.constants.XiuMuConst;
import com.xiumu.common.core.enums.AuthType;
import com.xiumu.common.core.enums.YesNo;
import com.xiumu.common.core.exception.user.AuthException;
import com.xiumu.common.core.page.PageQuery;
import com.xiumu.common.core.utils.AssertUtil;
import com.xiumu.dao.sys.AuthorityDao;
import com.xiumu.pojo.sys.dto.AuthorityDTO;
import com.xiumu.pojo.sys.entity.Authority;
import com.xiumu.pojo.sys.entity.Menu;
import com.xiumu.pojo.sys.query.AuthorityQuery;
import com.xiumu.pojo.sys.vo.AuthorityVO;
import com.xiumu.service.sys.AuthorityService;
import com.xiumu.service.sys.MenuService;
import com.xiumu.service.sys.RoleAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 权限 Service 业务层处理
 *
 * @author XiuMu
 * @date 2022-07-16 17:25:15
 */
@Service
public class AuthorityServiceImpl extends ServiceImpl<AuthorityDao, Authority> implements AuthorityService {

    @Autowired
    private MenuService menuService;

    @Autowired
    private RoleAuthService roleAuthService;

    @Override
    public Page<AuthorityVO> listPage(PageQuery<AuthorityQuery, Authority> pageQuery) {
        Page<Authority> authorityPage = this.baseMapper.selectPage(pageQuery.toPage(), pageQuery.getCondition());
        Page<AuthorityVO> voPage = new Page<AuthorityVO>();
        BeanUtil.copyProperties(authorityPage, voPage);
        voPage.setRecords(toAuthorityVO(authorityPage.getRecords()));
        return voPage;
    }

    @Override
    public List<AuthorityVO> listByAuthority(AuthorityQuery authority) {
        List<Authority> authorities = this.baseMapper.selectByAuthority(authority);
        return toAuthorityVO(authorities);
    }

    /**
     * 查询权限的菜单信息并将 Authority 转成 AuthorityVO
     *
     * @param authorities 权限集合
     * @return
     */
    private List<AuthorityVO> toAuthorityVO(List<Authority> authorities) {
        List<String> authCodeList = authorities.stream().filter(a -> a.getAuthType() == AuthType.MENU).map(Authority::getAuthCode).toList();
        List<Menu> menuList = menuService.listInAuthCodeList(authCodeList);
        List<AuthorityVO> voList = BeanUtil.copyToList(authorities, AuthorityVO.class);
        for (AuthorityVO vo : voList) {
            if (vo.getAuthType() == AuthType.MENU) {
                vo.setMenu(menuList.stream().filter(a -> a.getAuthCode().equals(vo.getAuthCode())).findAny().orElse(null));
            }
        }
        return voList;
    }

    @Override
    public List<Authority> listByUserId(Long userId) {
        return this.baseMapper.selectByUserId(userId);
    }

    @Override
    public List<String> listAuthCodeByUserId(Long userId) {
        return listByUserId(userId).stream().map(Authority::getAuthCode).toList();
    }

    @Override
    @Transactional
    public boolean create(AuthorityDTO authorityDTO) {
        Authority authority = BeanUtil.toBean(authorityDTO, Authority.class);
        // 根据该权限节点是不是菜单，如果是就保存菜单信息
        checkIsMenuAndSaveMenu(authorityDTO);
        return this.save(authority);
    }

    @Override
    @Transactional
    public boolean updateById(AuthorityDTO authorityDTO, Long id) {
        Authority authority = getById(id);
        AssertUtil.isNotNull(authority, AuthException.NOT_EXIT);
        // 根据该权限节点是不是菜单，如果是就保存菜单信息
        checkIsMenuAndSaveMenu(authorityDTO);
        authority = BeanUtil.copyProperties(authorityDTO, Authority.class);
        authority.setId(id);
        return updateById(authority);
    }

    @Override
    public boolean deleteById(Long id) {
        Authority authority = getById(id);
        AssertUtil.isNotNull(authority, AuthException.NOT_EXIT);
        // 判断是否有子级，有子级不可被删除
        boolean exists = this.baseMapper.exists(new LambdaUpdateWrapper<Authority>().eq(Authority::getParentId, id));
        AssertUtil.isFalse(exists, AuthException.AUTH_HAS_CHILDREN);
        // 删除菜单
        if (authority.getAuthType() == AuthType.MENU){
            menuService.remove(new LambdaQueryWrapper<Menu>().eq(Menu::getAuthCode, authority.getAuthCode()));
        }else {
            // 如果不是菜单，就看当前权限是否有角色绑定，如果有则不能删除
            AssertUtil.isTrue(roleAuthService.listByAuthId(id).isEmpty(), AuthException.AUTH_HAS_ROLE);
        }
        return this.remove(new LambdaQueryWrapper<Authority>().eq(Authority::getId, id));
    }

    @Override
    public List<Authority> listByRoleId(Long roleId) {
        return this.baseMapper.selectByRoleId(roleId);
    }

    @Override
    public List<Authority> listSubApiButtonAuthByParentId(Long parentId) {
        LambdaQueryWrapper<Authority> queryWrapper = new LambdaQueryWrapper<Authority>().eq(Authority::getParentId, parentId).ne(Authority::getAuthType, AuthType.MENU);
        return list(queryWrapper);
    }

    @Override
    public List<Authority> listApiButtonAuth() {
        LambdaQueryWrapper<Authority> queryWrapper = new LambdaQueryWrapper<Authority>().ne(Authority::getAuthType, AuthType.MENU);
        return list(queryWrapper);
    }

    /**
     * 重写 list 方法，查询未逻辑删除的记录
     *
     * @return
     */
    @Override
    public List<Authority> list() {
        LambdaQueryWrapper<Authority> queryWrapper = new LambdaQueryWrapper<Authority>().eq(Authority::getDeleteFlag, YesNo.NO);
        return this.baseMapper.selectList(queryWrapper);
    }

    /**
     * 重写 list 方法，查询未逻辑删除的记录
     *
     * @return
     */
    public List<Authority> list(LambdaQueryWrapper<Authority> queryWrapper) {
        if (ObjectUtil.isNull(queryWrapper)) {
            queryWrapper = new LambdaQueryWrapper<Authority>();
        }
        queryWrapper.eq(Authority::getDeleteFlag, YesNo.NO);
        return this.baseMapper.selectList(queryWrapper);
    }


    /**
     * 判断新增或修改的权限信息是不是菜单，如果是菜单就保存菜单信息
     *
     * @param authorityDTO 权限信息
     * @return 权限编码
     */
    public String checkIsMenuAndSaveMenu(AuthorityDTO authorityDTO) {
        String parentAuthCode = null;
        // 判断只有菜单才可以添加子级权限
        if (!authorityDTO.getParentId().equals(XiuMuConst.ZERO_LONG)) {
            Authority parent = getById(authorityDTO.getParentId());
            AssertUtil.isTrue(parent.getAuthType() == AuthType.MENU, AuthException.IS_NOT_MENU);
            parentAuthCode = parent.getAuthCode();
        }
        if (authorityDTO.getAuthType() == AuthType.MENU) {
            authorityDTO.getMenu().setWeight(authorityDTO.getWeight());
            menuService.saveOrUpdateByParentAuthIdAndAuthCodeAndMenuDTO(parentAuthCode, authorityDTO.getAuthCode(), authorityDTO.getMenu());
        }
        return parentAuthCode;
    }
}
